package net.pimpas.web.jsf.renderers.checkbox.ajax;

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;

import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.component.UISelectBoolean;
import javax.faces.component.UISelectMany;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.convert.Converter;
import javax.faces.model.SelectItem;
import javax.faces.model.SelectItemGroup;

import net.pimpas.util.reflection.ReflectionUtil;
import net.pimpas.web.jsf.renderers.AjaxRendererBase;
import net.pimpas.web.jsf.renderers.RendererBase;
import net.pimpas.web.jsf.util.ComponentUtils;

public class AjaxCheckboxRenderer extends RendererBase implements AjaxRendererBase {
	
	public static final String JAVASCRIPT_HANDLER	= "pimpas.AJAX.Populate.Checkbox";

	public String getJavascriptHandler() {
		return JAVASCRIPT_HANDLER;
	}
	
	@Override
	public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
		if(!component.isRendered()) return;
		if(!ComponentUtils.isCorrectComponentType(component, UIInput.class)) return;
		if(!ComponentUtils.isCorrectComponentType(component, UISelectBoolean.class) &&
				!ComponentUtils.isCorrectComponentType(component, UISelectMany.class)) return;
		
		ResponseWriter writer = context.getResponseWriter();
		writer.startElement("values", component);
		
		/**
		 * extracted from myfaces-1.1.5-SNAPSHOT 
		*/
		if (component instanceof UISelectBoolean) {
            Boolean value = org.apache.myfaces.shared_impl.renderkit.RendererUtils.getBooleanValue( component );
            boolean isChecked = value != null ? value.booleanValue() : false;
            if(isChecked) {
            	writer.startElement("value", component);
            	writer.write(value.toString());
            	writer.endElement("value");
            }
        } else if (component instanceof UISelectMany)
        	this.encodeSelectManyCheckBox( context, component );
		
		writer.endElement("values");
	}

	private void encodeSelectManyCheckBox(FacesContext context, UIComponent component) throws IOException {
		/**
		 * extracted from myfaces-1.1.5-SNAPSHOT
		 */
        Converter converter = null;
        
        UISelectMany many = (UISelectMany) component;
        
        converter = org.apache.myfaces.shared_impl.renderkit.RendererUtils.findUISelectManyConverter(context,
        		many);
        
        Set lookupSet = org.apache.myfaces.shared_impl.renderkit.RendererUtils.getSubmittedValuesAsSet(context, many, converter, many);
        boolean useSubmittedValues = lookupSet != null;

        if (!useSubmittedValues)
            lookupSet = org.apache.myfaces.shared_impl.renderkit.RendererUtils.getSelectedValuesAsSet(context, many, converter, many);

        for (Iterator it = org.apache.myfaces.shared_impl.renderkit.RendererUtils.getSelectItemList(many)
                .iterator(); it.hasNext();) {
            SelectItem selectItem = (SelectItem) it.next();
            
            this.renderGroupOrItemCheckbox(context, many, 
            		selectItem, useSubmittedValues, lookupSet, 
            		converter);
        }
	}

	private void renderGroupOrItemCheckbox(FacesContext context, UISelectMany many,
			SelectItem selectItem, boolean useSubmittedValues, Set lookupSet, Converter converter)
			throws IOException{
	   	Object itemValue = selectItem.getValue();
		String itemStrValue = null;
    	ResponseWriter writer = context.getResponseWriter();
    	
        if (converter == null)
            itemStrValue = itemValue.toString();
        else
            itemStrValue = converter.getAsString(context, many,
                    itemValue);
        
		if(ReflectionUtil.isSubclass(many.getClass(), SelectItemGroup.class)) {
			// group
			SelectItemGroup group = (SelectItemGroup) selectItem;
			for(int i=0;i<group.getSelectItems().length;i++)
				this.renderGroupOrItemCheckbox(context, many, group.getSelectItems()[i], useSubmittedValues, lookupSet, converter);
		} else {
	        boolean checked = lookupSet.contains(itemStrValue); 
	        if(checked) {
	        	writer.startElement("value", many);
	        	writer.write(itemStrValue);
	        	writer.endElement("value");
	        }
		}
	}
}